home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / ConfigSystem / main.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  59.5 KB  |  1,361 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: ConfigSystem.cpp
  3. //
  4. // This sample demonstrates a configuration system implementation that customizes
  5. // application behavior based on installed devices.
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved.
  8. //--------------------------------------------------------------------------------------
  9. #include "dxstdafx.h"
  10. #include <stdio.h>
  11. #include <shlobj.h>
  12. #include "resource.h"
  13. #include "ConfigDatabase.h"
  14. #include "ConfigManager.h"
  15.  
  16.  
  17. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  18. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  19.  
  20.  
  21. // MAXANISOTROPY is the maximum anisotropy state value used when anisotropic filtering is enabled.
  22. #define MAXANISOTROPY 8
  23.  
  24.  
  25. // -GROUND_Y is the Y coordinate of the ground.
  26. #define GROUND_Y 3.0f
  27.  
  28.  
  29. // GROUND_ABSORBANCE is the percentage of the velocity absorbed by ground and walls when an ammo hits.
  30. #define GROUND_ABSORBANCE 0.2f
  31.  
  32.  
  33. // AMMO_ABSORBANCE is the percentage of the velocity absorbed by ammos when two collide.
  34. #define AMMO_ABSORBANCE 0.1f
  35.  
  36.  
  37. // MAX_AMMO is the maximum number of ammo that can exist in the world.
  38. #define MAX_AMMO 50
  39.  
  40.  
  41. // AMMO_SIZE is the diameter of the ball mesh in the world.
  42. #define AMMO_SIZE 0.25f
  43.  
  44.  
  45. // AUTOFIRE_DELAY is the period between two successive ammo firing.
  46. #define AUTOFIRE_DELAY 0.1f
  47.  
  48.  
  49. // CAMERA_SIZE is used for clipping camera movement
  50. #define CAMERA_SIZE 0.2f
  51.  
  52.  
  53. // GRAVITY defines the magnitude of the downward force applied to ammos.
  54. #define GRAVITY 6.0f
  55.  
  56.  
  57. // BOUNCE_TRANSFER is the proportion of velocity transferred during a collision between 2 ammos.
  58. #define BOUNCE_TRANSFER 0.8f
  59.  
  60.  
  61. // BOUNCE_LOST is the proportion of velocity lost during a collision between 2 ammos.
  62. #define BOUNCE_LOST 0.1f
  63.  
  64.  
  65. // REST_THRESHOLD is the energy below which the ball is flagged as laying on ground.
  66. // It is defined as Gravity * Height_above_ground + 0.5 * Velocity * Velocity
  67. #define REST_THRESHOLD 0.005f
  68.  
  69.  
  70. // PHYSICS_FRAMELENGTH is the duration of a frame for physics handling
  71. // when the graphics frame length is too long.
  72. #define PHYSICS_FRAMELENGTH 0.003f
  73.  
  74.  
  75. // MAX_SOUND_VELOCITY is the velocity at which the bouncing sound is
  76. // played at maximum volume.  Higher velocity uses maximum volume.
  77. #define MAX_SOUND_VELOCITY 1.0f
  78.  
  79.  
  80. // MIN_SOUND_VELOCITY is the minimum contact velocity required to make a sound.
  81. #define MIN_SOUND_VELOCITY 0.07f
  82.  
  83.  
  84. // MIN_VOL_ADJUST is the minimum volume adjustment based on contact velocity.
  85. #define MIN_VOL_ADJUST 0.8f
  86.  
  87.  
  88. // MinBound and MaxBound are the bounding box representing the cell mesh.
  89. const D3DXVECTOR3 g_MinBound( -4.0f, -GROUND_Y, -6.0f );
  90. const D3DXVECTOR3 g_MaxBound( 4.0f, GROUND_Y, 6.0f );
  91.  
  92.  
  93. struct CBall
  94. {
  95.     D3DXVECTOR3 vPosition;
  96.     D3DXVECTOR3 vVelocity;
  97.     bool        bGround;    // Whether it is laying on the ground (resting or rolling)
  98.     CSound*     pSound;
  99.  
  100.     CBall() : bGround( false ), pSound( NULL ) { }
  101.     void PlaySound( float fImpactSpeed );
  102. };
  103.  
  104.  
  105. //--------------------------------------------------------------------------------------
  106. // Global variables
  107. //--------------------------------------------------------------------------------------
  108. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  109. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  110. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  111. IDirect3DTexture9*      g_pDefaultTex;          // Default texture for un-textured geometry.
  112. CFirstPersonCamera      g_Camera;               // Camera
  113. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  114. CDXUTDialog             g_HUD;                  // dialog for standard controls
  115. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  116. CConfigManager*         g_pCMList = NULL;       // Array of CConfigManager, one for each display device on system
  117. CConfigManager*         g_pCM = NULL;           // Active CM. Points to one of the elements in g_pCMList.
  118. CDXUTMesh               g_Cell;                 // Cell mesh object
  119. D3DXMATRIXA16           g_mCellWorld;           // World matrix for cell mesh
  120. CDXUTMesh               g_Ball;                 // Ball mesh object
  121. D3DXMATRIXA16           g_mBallWorld;           // World matrix for ball meshes (scaling)
  122. CBall                   g_AmmoQ[MAX_AMMO];      // Queue of ammos in the world
  123. int                     g_nAmmoCount = 0;       // Number of ammos that exist in the world
  124. int                     g_nAmmoListHead = 0;    // Head node of the queue
  125. int                     g_nAmmoListTail = 0;    // Tail node of the queue (1 past last instance)
  126. D3DXHANDLE              g_hShaderTech;          // Technique to use when using programmable rendering path
  127. D3DXHANDLE              g_hMatW;                // Handles to transformation matrices in effect
  128. D3DXHANDLE              g_hMatV;
  129. D3DXHANDLE              g_hMatP;
  130. D3DXHANDLE              g_hMatWV;
  131. D3DXHANDLE              g_hMatWVP;
  132. D3DXHANDLE              g_hDiffuse;             // Handles to material parameters in effect
  133. D3DXHANDLE              g_hSpecular;
  134. D3DXHANDLE              g_hTex;
  135. D3DXHANDLE              g_hPower;
  136. CSoundManager           g_SndMgr;
  137. bool                    g_bLeftMouseDown = false;
  138.  
  139.  
  140. //--------------------------------------------------------------------------------------
  141. // UI control IDs
  142. //--------------------------------------------------------------------------------------
  143. #define IDC_TOGGLEFULLSCREEN    1
  144. #define IDC_TOGGLEREF           2
  145. #define IDC_CHANGEDEVICE        3
  146. #define IDC_USEANISO            4
  147. #define IDC_FIXEDFUNC           5
  148. #define IDC_DISABLESPECULAR     6
  149. #define IDC_FORCESHADERTEXT     7
  150. #define IDC_FORCESHADER         8
  151.  
  152.  
  153. //--------------------------------------------------------------------------------------
  154. // Forward declarations 
  155. //--------------------------------------------------------------------------------------
  156. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  157. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  158. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  159. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  160. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  161. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  162. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  163. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  164. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  165. void    CALLBACK OnLostDevice();
  166. void    CALLBACK OnDestroyDevice();
  167.  
  168. void    InitApp();
  169. void    RenderText();
  170.  
  171.  
  172. void CBall::PlaySound( float fImpactSpeed )
  173. {
  174.     // Determine the sound volume adjustment based on velocity.
  175.     float fAdjustment;
  176.     if( fImpactSpeed < MIN_SOUND_VELOCITY )
  177.         fAdjustment = 0.0f;  // Too soft.  Don't play sound.
  178.     else
  179.     {
  180.         fAdjustment = min( 1.0f, fImpactSpeed / MAX_SOUND_VELOCITY );
  181.         // Rescale the adjustment so that its minimum is at 0.6.
  182.         fAdjustment = MIN_VOL_ADJUST + fAdjustment * ( 1.0f - MIN_VOL_ADJUST );
  183.     }
  184.     // Play sound
  185.     D3DXVECTOR3 vDistance = *g_Camera.GetEyePt() - vPosition;
  186.     float fVolume = min( D3DXVec3LengthSq( &vDistance ), 1.0f );
  187.     // Scale
  188.     fVolume *= -1800.f;
  189.     // Sound is proportional to how hard the ball is hitting.
  190.     fVolume = fAdjustment * ( fVolume - DSBVOLUME_MIN ) + DSBVOLUME_MIN;
  191.  
  192.     // Check pSound because it could be NULL. We allow the sample to run
  193.     // even if we cannot initialize sound.
  194.     if( pSound )
  195.     {
  196.         pSound->Reset();
  197.         pSound->Play( 0, 0, (LONG) fVolume );
  198.     }
  199. }
  200.  
  201.  
  202. //--------------------------------------------------------------------------------------
  203. // Entry point to the program. Initializes everything and goes into a message processing 
  204. // loop. Idle time is used to render the scene.
  205. //--------------------------------------------------------------------------------------
  206. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  207. {
  208.     HRESULT hr;
  209.     bool bSafeMode = false;
  210.  
  211.     // Set the callback functions. These functions allow the sample framework to notify
  212.     // the application about device changes, user input, and windows messages.  The 
  213.     // callbacks are optional so you need only set callbacks for events you're interested 
  214.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  215.     // framework won't be able to reset your device since the application must first 
  216.     // release all device resources before resetting.  Likewise, if you don't handle the 
  217.     // device created/destroyed callbacks then the sample framework won't be able to 
  218.     // recreate your device resources.
  219.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  220.     DXUTSetCallbackDeviceReset( OnResetDevice );
  221.     DXUTSetCallbackDeviceLost( OnLostDevice );
  222.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  223.     DXUTSetCallbackMsgProc( MsgProc );
  224.     DXUTSetCallbackKeyboard( KeyboardProc );
  225.     DXUTSetCallbackFrameRender( OnFrameRender );
  226.     DXUTSetCallbackFrameMove( OnFrameMove );
  227.  
  228.     // Show the cursor and clip it when in full screen
  229.     DXUTSetCursorSettings( true, true );
  230.  
  231.     // Application-specific initialization
  232.     InitApp();
  233.  
  234.     // Check for initialization flag from previous launch.
  235.     // We use SHGetFolderPath with CSIDL_LOCAL_APPDATA to write to
  236.     // a subdirectory of Documents and Settings\<username>\Local Settings\Application Data.
  237.     // It is the best practice to write user-specific data under the user profile directory
  238.     // because not every user on the system will always have write access to the application
  239.     // executable directory.
  240.     WCHAR wszPath[MAX_PATH];
  241.     ::GetModuleFileName( NULL, wszPath, MAX_PATH );
  242.     hr = ::SHGetFolderPath( NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wszPath );
  243.     if( SUCCEEDED( hr ) )
  244.     {
  245.         // Create the directory for this application. We don't care
  246.         // if the directory already exists as long as it exists after
  247.         // this point.
  248.         lstrcatW( wszPath, L"\\ConfigSystem" );
  249.         CreateDirectory( wszPath, NULL );
  250.  
  251.         // Check for launch.sta
  252.         lstrcatW( wszPath, L"\\Launch.sta" );
  253.         if( ::GetFileAttributes( wszPath ) != INVALID_FILE_ATTRIBUTES )
  254.         {
  255.             // Launch.sta exists.  Most likely previous launch did not succeed.
  256.             // Prompt the user to enter safe mode.
  257.             if( IDYES == ::MessageBox( NULL, L"The application failed to initialize during "
  258.                                             L"the previous launch.  It is recommended that "
  259.                                             L"you run the application in safe mode.\n\n"
  260.                                             L"Do you wish to run in safe mode?",
  261.                                             L"ConfigSystem", MB_YESNO|MB_ICONQUESTION ) )
  262.                 bSafeMode = true;
  263.         }
  264.         else
  265.         {
  266.             // Create Launch.sta in the executable folder.
  267.             HANDLE hFile = ::CreateFile( wszPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  268.             if( hFile != INVALID_HANDLE_VALUE )
  269.                 ::CloseHandle( hFile );
  270.         }
  271.     }
  272.  
  273.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  274.     // device for the application. Calling each of these functions is optional, but they
  275.     // allow you to set several options which control the behavior of the framework.
  276.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  277.  
  278.     //
  279.     // Initialize config information for all available 3D devices after DXUTInit is called
  280.     // because we would like to do this as soon as we have a D3D object.
  281.     IDirect3D9 *pD3D = DXUTGetD3DObject();
  282.     assert( pD3D != NULL );
  283.  
  284.     // Allocate the CM array to hold all devices on the system.
  285.     g_pCMList = new CConfigManager[pD3D->GetAdapterCount()];
  286.     if( !g_pCMList )
  287.     {
  288.         // If we cannot allocate memory for the CM array.  The system must
  289.         // be in a critical state.  Do not proceed in this case.
  290.         ::MessageBox( NULL, L"The system has insufficient memory to run the application.", L"ConfigSystem", MB_OK );
  291.     }
  292.     else
  293.     {
  294.         // Obtain sound information (device GUID)
  295.         GUID guidDeviceId;
  296.         GetDeviceID( &DSDEVID_DefaultPlayback, &guidDeviceId );
  297.  
  298.         WCHAR str[MAX_PATH];
  299.         DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"config.txt" );
  300.  
  301.         // Initialize CM objects, one for each 3D device
  302.         for( DWORD dev = 0; dev < pD3D->GetAdapterCount(); ++dev )
  303.         {
  304.             D3DADAPTER_IDENTIFIER9 id;
  305.             D3DCAPS9 Caps;
  306.             pD3D->GetAdapterIdentifier( dev, 0, &id );
  307.             pD3D->GetDeviceCaps( dev, D3DDEVTYPE_HAL, &Caps );
  308.             g_pCMList[dev].Initialize( str, id, Caps, guidDeviceId );
  309.             // Propagate safe mode flag
  310.             g_pCMList[dev].cf_SafeMode = bSafeMode;
  311.         }
  312.  
  313.         // Make g_pCM point to the first element in g_pCMList by default.
  314.         // OnCreateDevice will make it point to the correct element later.
  315.         g_pCM = g_pCMList;
  316.  
  317.         // Handle window creation
  318.         DXUTCreateWindow( L"ConfigSystem" );
  319.  
  320.         // Initialize sound after we have the window
  321.         WCHAR wszBounce[MAX_PATH];
  322.         g_SndMgr.Initialize( DXUTGetHWND(), DSSCL_PRIORITY );
  323.         DXUTFindDXSDKMediaFileCch( wszBounce, MAX_PATH, L"bounce.wav" );
  324.         for( int A = 0; A < MAX_AMMO; ++A )
  325.         {
  326.             hr = g_SndMgr.Create( &g_AmmoQ[A].pSound, wszBounce, DSBCAPS_CTRLVOLUME );
  327.             if( FAILED( hr ) )
  328.                 break;
  329.         }
  330.  
  331.         if( SUCCEEDED( hr ) )
  332.             hr = DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  333.  
  334.         // Pass control to the sample framework for handling the message pump and 
  335.         // dispatching render calls. The sample framework will call your FrameMove 
  336.         // and FrameRender callback when there is idle time between handling window messages.
  337.         DXUTMainLoop();
  338.  
  339.         delete[] g_pCMList;
  340.  
  341.         if( SUCCEEDED( hr ) )
  342.         {
  343.             // Program completed.  Remove Launch.sta
  344.             ::DeleteFile( wszPath );
  345.         }
  346.     }
  347.  
  348.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  349.     // appropriate callback functions and therefore don't require any cleanup code here.
  350.     for( int A = 0; A < MAX_AMMO; ++A )
  351.         delete g_AmmoQ[A].pSound;
  352.  
  353.     return DXUTGetExitCode();
  354. }
  355.  
  356.  
  357. //--------------------------------------------------------------------------------------
  358. // Initialize the app 
  359. //--------------------------------------------------------------------------------------
  360. void InitApp()
  361. {
  362.     // Initialize dialogs
  363.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  364.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  365.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  366.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  367.  
  368.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 0;
  369.     g_SampleUI.AddStatic( IDC_FORCESHADERTEXT, L"Force shader version:", 15, iY, 145, 22 );
  370.     g_SampleUI.AddComboBox( IDC_FORCESHADER, 15, iY += 24, 145, 22 );
  371.     g_SampleUI.AddCheckBox( IDC_USEANISO, L"Use anisotropic filtering", 15, iY += 24, 145, 22 );
  372.     g_SampleUI.AddCheckBox( IDC_FIXEDFUNC, L"Use fixed-function", 15, iY += 24, 145, 22 );
  373.     g_SampleUI.AddCheckBox( IDC_DISABLESPECULAR, L"Disable specular lighting", 15, iY += 24, 145, 22 );
  374.     // Populate the combo box with shader rendering techniques
  375.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"Card maximum", (LPVOID)0 );
  376.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"3.0", (LPVOID)30 );
  377.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"2.a", (LPVOID)9998 );
  378.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"2.b", (LPVOID)9997 );
  379.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"2.0", (LPVOID)20 );
  380.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"1.4", (LPVOID)14 );
  381.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"1.3", (LPVOID)13 );
  382.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"1.2", (LPVOID)12 );
  383.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"1.1", (LPVOID)11 );
  384.     g_SampleUI.GetComboBox( IDC_FORCESHADER )->AddItem( L"Do not use shader", (LPVOID)9999 );
  385.  
  386.     // Setup the camera
  387.     D3DXVECTOR3 MinBound( g_MinBound.x + CAMERA_SIZE, g_MinBound.y + CAMERA_SIZE, g_MinBound.z + CAMERA_SIZE );
  388.     D3DXVECTOR3 MaxBound( g_MaxBound.x - CAMERA_SIZE, g_MaxBound.y - CAMERA_SIZE, g_MaxBound.z - CAMERA_SIZE );
  389.     g_Camera.SetClipToBoundary( true, &MinBound, &MaxBound );
  390.     g_Camera.SetEnableYAxisMovement( false );
  391.     g_Camera.SetRotateButtons( false, false, true );
  392.     g_Camera.SetScalers( 0.01f, 2.0f );
  393.     D3DXVECTOR3 vecEye(0.0f, -GROUND_Y + 0.7f, 0.0f);
  394.     D3DXVECTOR3 vecAt (0.0f, -GROUND_Y + 0.7f, 1.0f);
  395.     g_Camera.SetViewParams( &vecEye, &vecAt );
  396.  
  397.     // Initialize world matrices
  398.     D3DXMatrixScaling( &g_mCellWorld, 1.0f, GROUND_Y / 3.0f, 1.0f );
  399.  
  400.     // Initialize some instances of ammo so it's easier for users to
  401.     // figure out what to do at the start.
  402.     D3DXVECTOR4 Pos( 0.0f, -GROUND_Y - 2 * AMMO_SIZE, AMMO_SIZE, 1.0f );
  403.     D3DXVECTOR4 Vel( 0.0f, 4.25f, 4.25f, 1.0f );
  404.     D3DXMATRIXA16 m;
  405.     D3DXMatrixRotationY( &m, D3DX_PI / 6 );  // Matrix to rotate vel vector
  406.     for( int A = 0; A < 12; ++A )
  407.     {
  408.         g_AmmoQ[A].bGround = false;
  409.         g_AmmoQ[A].vPosition = (D3DXVECTOR3)Pos;
  410.         g_AmmoQ[A].vVelocity = (D3DXVECTOR3)Vel;
  411.         D3DXVec4Transform( &Pos, &Pos, &m );
  412.         D3DXVec4Transform( &Vel, &Vel, &m );
  413.     }
  414.     g_nAmmoCount = 12;
  415.     g_nAmmoListTail = 12;
  416. }
  417.  
  418.  
  419. //--------------------------------------------------------------------------------------
  420. // Called during device initialization, this code checks the device for some 
  421. // minimum set of capabilities, and rejects those that don't pass by returning false.
  422. //--------------------------------------------------------------------------------------
  423. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  424.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  425. {
  426.     // Skip backbuffer formats that don't support alpha blending
  427.     IDirect3D9* pD3D = DXUTGetD3DObject();
  428.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  429.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  430.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  431.         return false;
  432.  
  433.     return true;
  434. }
  435.  
  436.  
  437. //--------------------------------------------------------------------------------------
  438. // This callback function is called immediately before a device is created to allow the 
  439. // application to modify the device settings. The supplied pDeviceSettings parameter 
  440. // contains the settings that the framework has selected for the new device, and the 
  441. // application can make any desired changes directly to this structure.  Note however that 
  442. // the sample framework will not correct invalid device settings so care must be taken 
  443. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  444. //--------------------------------------------------------------------------------------
  445. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  446. {
  447.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  448.     // then switch to SWVP.
  449.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  450.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  451.     {
  452.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  453.     }
  454.     else
  455.     {
  456.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  457.     }
  458.  
  459.     // This application is designed to work on a pure device by not using 
  460.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  461.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  462.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  463.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  464.  
  465.     // Debugging vertex shaders requires either REF or software vertex processing 
  466.     // and debugging pixel shaders requires REF.  
  467. #ifdef DEBUG_VS
  468.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  469.     {
  470.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  471.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
  472.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  473.     }
  474. #endif
  475. #ifdef DEBUG_PS
  476.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  477. #endif
  478. }
  479.  
  480.  
  481. //--------------------------------------------------------------------------------------
  482. // Compute a matrix that scales Mesh to a specified size and centers around origin
  483. void ComputeMeshScaling( CDXUTMesh &Mesh, D3DXMATRIX *pmScalingCenter, float fNewRadius )
  484. {
  485.     LPVOID pVerts = NULL;
  486.     D3DXMatrixIdentity( pmScalingCenter );
  487.     if( SUCCEEDED( Mesh.GetSysMemMesh()->LockVertexBuffer( 0, &pVerts ) ) )
  488.     {
  489.         D3DXVECTOR3 vCtr;
  490.         float fRadius;
  491.         if( SUCCEEDED( D3DXComputeBoundingSphere( (const D3DXVECTOR3*)pVerts,
  492.                                                   Mesh.GetSysMemMesh()->GetNumVertices(),
  493.                                                   Mesh.GetSysMemMesh()->GetNumBytesPerVertex(),
  494.                                                   &vCtr, &fRadius ) ) )
  495.         {
  496.             D3DXMatrixTranslation( pmScalingCenter, -vCtr.x, -vCtr.y, -vCtr.z );
  497.             D3DXMATRIXA16 m;
  498.             D3DXMatrixScaling( &m, fNewRadius / fRadius,
  499.                                    fNewRadius / fRadius,
  500.                                    fNewRadius / fRadius );
  501.             D3DXMatrixMultiply( pmScalingCenter, pmScalingCenter, &m );
  502.         }
  503.         Mesh.GetSysMemMesh()->UnlockVertexBuffer();
  504.     }
  505. }
  506.  
  507.  
  508. void SetEffectTechnique()
  509. {
  510.     if( g_pCM->cf_UseFixedFunction )
  511.         g_pEffect->SetTechnique( "FFRenderScene" );
  512.     else
  513.     {
  514.         // For programmable pipeline, check for shader version override (ForceShader).
  515.         switch( g_pCM->cf_ForceShader )
  516.         {
  517.             case 9999:
  518.                 // 9999 is a code to mean "do not use shader"
  519.                 g_hShaderTech = g_pEffect->GetTechniqueByName( "FFRenderScene" );
  520.                 break;
  521.  
  522.             case 9998:
  523.                 // 9998 is a code to represent shader 2_a
  524.                 g_hShaderTech = g_pEffect->GetTechniqueByName( "RenderScenePS20A" );
  525.                 break;
  526.  
  527.             case 9997:
  528.                 // 9997 is a code to represent shader 2_b
  529.                 g_hShaderTech = g_pEffect->GetTechniqueByName( "RenderScenePS20B" );
  530.                 break;
  531.  
  532.             case 0:
  533.                 // 0 means use the highest valid technique.
  534.                 g_pEffect->FindNextValidTechnique( NULL, &g_hShaderTech );
  535.                 break;
  536.  
  537.             // In all other cases, g_pCM->cf_ForceShader defines a shader version
  538.             // this way: g_pCM->cf_ForceShader = MAJOR * 10 + MINOR
  539.             default:
  540.             {
  541.                 char szTechName[50];
  542.  
  543.                 _snprintf( szTechName, 50, "RenderScenePS%d", g_pCM->cf_ForceShader );
  544.                 szTechName[49] = '\0';
  545.                 g_hShaderTech = g_pEffect->GetTechniqueByName( szTechName );
  546.                 break;
  547.             }
  548.         }
  549.  
  550.         g_pEffect->SetTechnique( g_hShaderTech );
  551.     }
  552. }
  553.  
  554.  
  555. //--------------------------------------------------------------------------------------
  556. // This callback function will be called immediately after the Direct3D device has been 
  557. // created, which will happen during application initialization and windowed/full screen 
  558. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  559. // resources need to be reloaded whenever the device is destroyed. Resources created  
  560. // here should be released in the OnDestroyDevice callback. 
  561. //--------------------------------------------------------------------------------------
  562. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  563. {
  564.     HRESULT hr;
  565.  
  566.     //
  567.     // Obtain the CConfigManager object for the 3D device created.
  568.     // Point g_pCM to the CConfigManager object.
  569.     D3DCAPS9 Caps;
  570.     pd3dDevice->GetDeviceCaps( &Caps );
  571.     g_pCM = g_pCMList + Caps.AdapterOrdinal;
  572.  
  573.     // Verify requirement and prompt the user if any requirement is not met.
  574.     hr = g_pCM->VerifyRequirements();
  575.     if( FAILED( hr ) )
  576.         return hr;
  577.  
  578.     // Check for unsupported display device.
  579.     if( g_pCM->cf_UnsupportedCard )
  580.     {
  581.         ::MessageBox( NULL, L"The display device is not supported by this application. "
  582.                             L"The program will now exit.", L"ConfigSystem", MB_OK|MB_ICONERROR );
  583.         return E_FAIL;
  584.     }
  585.  
  586.     // Check for invalid display driver
  587.     if( g_pCM->cf_InvalidDriver )
  588.     {
  589.         ::MessageBox( NULL, L"The display driver detected is incompatible with this application. "
  590.                             L"The program will now exit.", L"ConfigSystem", MB_OK|MB_ICONERROR );
  591.         return E_FAIL;
  592.     }
  593.  
  594.     // Check for old display driver
  595.     if( g_pCM->cf_OldDriver )
  596.     {
  597.         ::MessageBox( NULL, L"The display driver is out-of-date. We recommend that you "
  598.                             L"install the latest driver for this display device.",
  599.                             L"ConfigSystem", MB_OK|MB_ICONWARNING );
  600.     }
  601.  
  602.     // Check for known prototype card
  603.     if( g_pCM->cf_PrototypeCard )
  604.     {
  605.         ::MessageBox( NULL, L"A prototype display card is detected.  We recommend using "
  606.                             L"only supported retail display cards to run this application.",
  607.                             L"ConfigSystem", MB_OK|MB_ICONWARNING );
  608.     }
  609.  
  610.     // Check for invalid sound driver
  611.     if( g_pCM->cf_InvalidSoundDriver )
  612.     {
  613.         ::MessageBox( NULL, L"The sound driver detected is incompatible with this application. "
  614.                             L"The program will now exit.", L"ConfigSystem", MB_OK|MB_ICONERROR );
  615.         return E_FAIL;
  616.     }
  617.  
  618.     // Check for old sound driver
  619.     if( g_pCM->cf_OldSoundDriver )
  620.     {
  621.         ::MessageBox( NULL, L"The sound driver is out-of-date. We recommend that you "
  622.                             L"install the latest driver for this sound device.",
  623.                             L"ConfigSystem", MB_OK|MB_ICONWARNING );
  624.     }
  625.  
  626.     // Go through the list of resolution and remove those that are excluded for this card.
  627.     CD3DEnumAdapterInfo* pAdapterInfo = DXUTGetEnumeration()->GetAdapterInfo( Caps.AdapterOrdinal );
  628.     for( int idm = pAdapterInfo->displayModeList.GetSize() - 1; idm >= 0; --idm )
  629.     {
  630.         D3DDISPLAYMODE DisplayMode = pAdapterInfo->displayModeList.GetAt( idm );
  631.  
  632.         if( DisplayMode.Width > g_pCM->cf_MaximumResolution )
  633.             pAdapterInfo->displayModeList.Remove( idm );
  634.     }
  635.  
  636.     // Update the UI elements to reflect correct config flag values.
  637.     g_SampleUI.GetCheckBox( IDC_USEANISO )->SetChecked( g_pCM->cf_UseAnisotropicFilter != 0 );
  638.     g_SampleUI.GetCheckBox( IDC_FIXEDFUNC )->SetChecked( g_pCM->cf_UseFixedFunction != 0 );
  639.  
  640.     // Initialize the font
  641.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  642.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  643.                          L"Arial", &g_pFont ) );
  644.  
  645.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  646.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  647.     // processing, and debugging pixel shaders requires REF.  The 
  648.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  649.     // shader debugger.  It enables source level debugging, prevents instruction 
  650.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  651.     // against the next higher available software target, which ensures that the 
  652.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  653.     // flags will cause slower rendering since the shaders will be unoptimized and 
  654.     // forced into software.  See the DirectX documentation for more information about 
  655.     // using the shader debugger.
  656.     DWORD dwShaderFlags = 0;
  657.     #ifdef DEBUG_VS
  658.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  659.     #endif
  660.     #ifdef DEBUG_PS
  661.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  662.     #endif
  663.  
  664.     // Read the D3DX effect file
  665.     WCHAR str[MAX_PATH];
  666.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Main.fx" ) );
  667.  
  668.     // If this fails, there should be debug output as to 
  669.     // they the .fx file failed to compile
  670.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  671.                                         NULL, &g_pEffect, NULL ) );
  672.  
  673.     // Obtain handles
  674.     g_hMatW = g_pEffect->GetParameterByName( NULL, "g_mWorld" );
  675.     g_hMatV = g_pEffect->GetParameterByName( NULL, "g_mView" );
  676.     g_hMatP = g_pEffect->GetParameterByName( NULL, "g_mProj" );
  677.     g_hMatWV = g_pEffect->GetParameterByName( NULL, "g_mWorldView" );
  678.     g_hMatWVP = g_pEffect->GetParameterByName( NULL, "g_mWorldViewProj" );
  679.     g_hDiffuse = g_pEffect->GetParameterByName( NULL, "g_matDiffuse" );
  680.     g_hSpecular = g_pEffect->GetParameterByName( NULL, "g_matSpecular" );
  681.     g_hTex = g_pEffect->GetParameterByName( NULL, "g_txScene" );
  682.     g_hPower = g_pEffect->GetParameterByName( NULL, "g_matPower" );
  683.  
  684.     // Create mesh
  685.     WCHAR wsz[MAX_PATH];
  686.     V_RETURN( DXUTFindDXSDKMediaFileCch( wsz, MAX_PATH, L"misc\\cell.x" ) );
  687.     g_Cell.Create( pd3dDevice, wsz );
  688.     // Tessellate the mesh for better per-vertex lighting result.
  689.     ID3DXMesh *pTessMesh;
  690.     D3DXTessellateNPatches( g_Cell.m_pSysMemMesh, NULL, 8, false, &pTessMesh, NULL );
  691.     g_Cell.m_pSysMemMesh->Release();
  692.     g_Cell.m_pSysMemMesh = pTessMesh;
  693.  
  694.     V_RETURN( DXUTFindDXSDKMediaFileCch( wsz, MAX_PATH, L"ball.x" ) );
  695.     g_Ball.Create( pd3dDevice, wsz );
  696.  
  697.     // Create the 1x1 white default texture
  698.     V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, 0, D3DFMT_A8R8G8B8,
  699.                                          D3DPOOL_MANAGED, &g_pDefaultTex, NULL ) );
  700.     D3DLOCKED_RECT lr;
  701.     V_RETURN( g_pDefaultTex->LockRect( 0, &lr, NULL, 0 ) );
  702.     *(LPDWORD)lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );
  703.     V_RETURN( g_pDefaultTex->UnlockRect( 0 ) );
  704.  
  705.     // Compute the scaling matrix for the ball mesh.
  706.     ComputeMeshScaling( g_Ball, &g_mBallWorld, AMMO_SIZE * 0.5f );
  707.  
  708.     //
  709.     // Initialize feature usage settings in the effect object according to the config flags.
  710.     //
  711.  
  712.     // Rendering technique (FF or shader)
  713.     SetEffectTechnique();
  714.  
  715.     // Specular lighting
  716.     g_pEffect->SetBool( "g_bUseSpecular", !g_pCM->cf_DisableSpecular );
  717.  
  718.     // Anisotropic filtering
  719.     g_pEffect->SetBool( "g_bUseAnisotropic", g_pCM->cf_UseAnisotropicFilter );
  720.     g_pEffect->SetInt( "g_MinFilter", g_pCM->cf_UseAnisotropicFilter ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR );
  721.     g_pEffect->SetInt( "g_MaxAnisotropy", g_pCM->cf_UseAnisotropicFilter ? 8 : 1 );
  722.  
  723.     return S_OK;
  724. }
  725.  
  726.  
  727. //--------------------------------------------------------------------------------------
  728. // This callback function will be called immediately after the Direct3D device has been 
  729. // reset, which will happen after a lost device scenario. This is the best location to 
  730. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  731. // the device is lost. Resources created here should be released in the OnLostDevice 
  732. // callback. 
  733. //--------------------------------------------------------------------------------------
  734. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  735.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  736. {
  737.     HRESULT hr;
  738.  
  739.     if( g_pFont )
  740.         V_RETURN( g_pFont->OnResetDevice() );
  741.     if( g_pEffect )
  742.         V_RETURN( g_pEffect->OnResetDevice() );
  743.  
  744.     g_Cell.RestoreDeviceObjects( pd3dDevice );
  745.     g_Ball.RestoreDeviceObjects( pd3dDevice );
  746.  
  747.     // Create a sprite to help batch calls when drawing many lines of text
  748.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  749.  
  750.     // Setup the camera's projection parameters
  751.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  752.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
  753.  
  754.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  755.     g_HUD.SetSize( 170, 170 );
  756.     g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-230 );
  757.     g_SampleUI.SetSize( 170, 300 );
  758.  
  759.     return S_OK;
  760. }
  761.  
  762.  
  763. //--------------------------------------------------------------------------------------
  764. // This callback function will be called once at the beginning of every frame. This is the
  765. // best location for your application to handle updates to the scene, but is not 
  766. // intended to contain actual rendering calls, which should instead be placed in the 
  767. // OnFrameRender callback.  
  768. //--------------------------------------------------------------------------------------
  769. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  770. {
  771.     // Update the camera's position based on user input 
  772.     g_Camera.FrameMove( fElapsedTime );
  773.  
  774.     // Check mouse and shoot ammo
  775.     if( g_bLeftMouseDown )
  776.     {
  777.         static float fLastFired;  // Timestamp of last ammo fired
  778.  
  779.         if( fTime - fLastFired >= AUTOFIRE_DELAY )
  780.         {
  781.             // Check to see if there are already MAX_AMMO balls in the world.
  782.             // Remove the oldest ammo to make room for the newest if necessary.
  783.             if( g_nAmmoCount == MAX_AMMO )
  784.             {
  785.                 g_nAmmoListHead = ( g_nAmmoListHead + 1 ) % MAX_AMMO;
  786.                 --g_nAmmoCount;
  787.             }
  788.  
  789.             // Get inverse view matrix
  790.             D3DXMATRIXA16 mInvView;
  791.             D3DXMatrixInverse( &mInvView, NULL, g_Camera.GetViewMatrix() );
  792.  
  793.             // Compute initial velocity in world space from camera space
  794.             D3DXVECTOR4 InitialVelocity( 0.0f, 0.0f, 6.0f, 0.0f );
  795.             D3DXVec4Transform( &InitialVelocity, &InitialVelocity, &mInvView );
  796.  
  797.             // Populate velocity
  798.             g_AmmoQ[g_nAmmoListTail].vVelocity.x = InitialVelocity.x;
  799.             g_AmmoQ[g_nAmmoListTail].vVelocity.y = InitialVelocity.y;
  800.             g_AmmoQ[g_nAmmoListTail].vVelocity.z = InitialVelocity.z;
  801.  
  802.             // Populate position
  803.             D3DXVECTOR4 InitialPosition( 0.0f, -0.15f, 0.0f, 1.0f );
  804.             D3DXVec4Transform( &InitialPosition, &InitialPosition, &mInvView );
  805.             g_AmmoQ[g_nAmmoListTail].vPosition.x = InitialPosition.x;
  806.             g_AmmoQ[g_nAmmoListTail].vPosition.y = InitialPosition.y;
  807.             g_AmmoQ[g_nAmmoListTail].vPosition.z = InitialPosition.z;
  808.  
  809.             // Initially not laying on ground
  810.             g_AmmoQ[g_nAmmoListTail].bGround = false;
  811.  
  812.             // Increment tail
  813.             g_nAmmoListTail = ( g_nAmmoListTail + 1 ) % MAX_AMMO;
  814.             ++g_nAmmoCount;
  815.  
  816.             fLastFired = (float)fTime;
  817.         }
  818.     }
  819.  
  820.     // Animate the ammo
  821.     if( g_nAmmoCount > 0 )
  822.     {
  823.         // Check for inter-ammo collision
  824.         if( g_nAmmoCount > 1 )
  825.         {
  826.             for( int One = g_nAmmoListHead; ; )
  827.             {
  828.                 for( int Two = ( One + 1 ) % MAX_AMMO; ; )
  829.                 {
  830.                     // Check collision between instances One and Two.
  831.                     // vOneToTwo is the collision normal vector.
  832.                     D3DXVECTOR3 vOneToTwo = g_AmmoQ[Two].vPosition - g_AmmoQ[One].vPosition;
  833.                     float DistSq = D3DXVec3LengthSq( &vOneToTwo );
  834.                     if( DistSq < AMMO_SIZE * AMMO_SIZE )
  835.                     {
  836.                         D3DXVec3Normalize( &vOneToTwo, &vOneToTwo );
  837.  
  838.                         // Check if the two instances are already moving away from each other.
  839.                         // If so, skip collision.  This can happen when a lot of instances are
  840.                         // bunched up next to each other.
  841.                         float fImpact = D3DXVec3Dot( &vOneToTwo, &g_AmmoQ[One].vVelocity ) - D3DXVec3Dot( &vOneToTwo, &g_AmmoQ[Two].vVelocity );
  842.                         if( fImpact > 0.0f )
  843.                         {
  844.                             // Compute the normal and tangential components of One's velocity.
  845.                             D3DXVECTOR3 vVelocityOneN = ( 1 - BOUNCE_LOST ) * D3DXVec3Dot( &vOneToTwo, &g_AmmoQ[One].vVelocity ) * vOneToTwo;
  846.                             D3DXVECTOR3 vVelocityOneT = ( 1 - BOUNCE_LOST ) * g_AmmoQ[One].vVelocity - vVelocityOneN;
  847.                             // Compute the normal and tangential components of Two's velocity.
  848.                             D3DXVECTOR3 vVelocityTwoN = ( 1 - BOUNCE_LOST ) * D3DXVec3Dot( &vOneToTwo, &g_AmmoQ[Two].vVelocity ) * vOneToTwo;
  849.                             D3DXVECTOR3 vVelocityTwoT = ( 1 - BOUNCE_LOST ) * g_AmmoQ[Two].vVelocity - vVelocityTwoN;
  850.  
  851.                             // Compute post-collision velocity
  852.                             g_AmmoQ[One].vVelocity = vVelocityOneT - vVelocityOneN * ( 1 - BOUNCE_TRANSFER ) + vVelocityTwoN * BOUNCE_TRANSFER;
  853.                             g_AmmoQ[Two].vVelocity = vVelocityTwoT - vVelocityTwoN * ( 1 - BOUNCE_TRANSFER ) + vVelocityOneN * BOUNCE_TRANSFER;
  854.  
  855.                             // Fix the positions so that the two balls are exactly AMMO_SIZE apart.
  856.                             float fDistanceToMove = ( AMMO_SIZE - sqrtf( DistSq ) ) * 0.5f;
  857.                             g_AmmoQ[One].vPosition -= vOneToTwo * fDistanceToMove;
  858.                             g_AmmoQ[Two].vPosition += vOneToTwo * fDistanceToMove;
  859.  
  860.                             // Flag the two instances so that they are not laying on ground.
  861.                             g_AmmoQ[One].bGround = g_AmmoQ[Two].bGround = false;
  862.  
  863.                             // Play sound
  864.                             g_AmmoQ[One].PlaySound( fImpact );
  865.                             g_AmmoQ[Two].PlaySound( fImpact );
  866.                         }
  867.                     }
  868.  
  869.                     Two = ( Two + 1 ) % MAX_AMMO;
  870.                     if( Two == g_nAmmoListTail )
  871.                         break;
  872.                 }
  873.  
  874.                 One = ( One + 1 ) % MAX_AMMO;
  875.                 if( ( One + 1 ) % MAX_AMMO == g_nAmmoListTail )
  876.                     break;
  877.             }
  878.         }
  879.  
  880.         // Apply gravity and check for collision against ground and walls.
  881.         for( int A = g_nAmmoListHead; ; )
  882.         {
  883.             // If the elapsed time is too long, we slice up the time and
  884.             // handle physics over several passes.
  885.             float fTimeLeft = fElapsedTime;
  886.             float fElapsedFrameTime;
  887.  
  888.             while( fTimeLeft > 0.0f )
  889.             {
  890.                 fElapsedFrameTime = min( fTimeLeft, PHYSICS_FRAMELENGTH );
  891.                 fTimeLeft -= fElapsedFrameTime;
  892.  
  893.                 g_AmmoQ[A].vPosition += g_AmmoQ[A].vVelocity * fElapsedFrameTime;
  894.  
  895.                 g_AmmoQ[A].vVelocity.x -= g_AmmoQ[A].vVelocity.x * 0.1f * fElapsedFrameTime;
  896.                 g_AmmoQ[A].vVelocity.z -= g_AmmoQ[A].vVelocity.z * 0.1f * fElapsedFrameTime;
  897.                 // Apply gravity if the ball is not resting on the ground.
  898.                 if( !g_AmmoQ[A].bGround )
  899.                 {
  900.                     g_AmmoQ[A].vVelocity.y -= GRAVITY * fElapsedFrameTime;
  901.                 }
  902.  
  903.                 // Check bounce on ground
  904.                 if( !g_AmmoQ[A].bGround )
  905.                 {
  906.                     if( g_AmmoQ[A].vPosition.y < -GROUND_Y + ( AMMO_SIZE * 0.5f ) )
  907.                     {
  908.                         // Align the ball with the ground.
  909.                         g_AmmoQ[A].vPosition.y = -GROUND_Y + ( AMMO_SIZE * 0.5f );
  910.  
  911.                         // Play sound
  912.                         g_AmmoQ[A].PlaySound( -g_AmmoQ[A].vVelocity.y );
  913.  
  914.                         // Invert the Y velocity
  915.                         g_AmmoQ[A].vVelocity.y = -g_AmmoQ[A].vVelocity.y * ( 1 - GROUND_ABSORBANCE );
  916.  
  917.                         // X and Z velocity are reduced because of friction.
  918.                         g_AmmoQ[A].vVelocity.x *= 0.9f;
  919.                         g_AmmoQ[A].vVelocity.z *= 0.9f;
  920.                     }
  921.                 }
  922.                 else
  923.                 {
  924.                     // Ball is resting or rolling on ground.
  925.                     // X and Z velocity are reduced because of friction.
  926.                     g_AmmoQ[A].vVelocity.x *= 0.9f;
  927.                     g_AmmoQ[A].vVelocity.z *= 0.9f;
  928.                 }
  929.  
  930.                 // Check bounce on ceiling
  931.                 if( g_AmmoQ[A].vPosition.y > GROUND_Y - ( AMMO_SIZE * 0.5f ) )
  932.                 {
  933.                     // Align the ball with the ground.
  934.                     g_AmmoQ[A].vPosition.y = GROUND_Y - ( AMMO_SIZE * 0.5f );
  935.  
  936.                     // Play sound
  937.                     g_AmmoQ[A].PlaySound( g_AmmoQ[A].vVelocity.y );
  938.  
  939.                     // Invert the Y velocity
  940.                     g_AmmoQ[A].vVelocity.y = -g_AmmoQ[A].vVelocity.y * ( 1 - GROUND_ABSORBANCE );
  941.  
  942.                     // X and Z velocity are reduced because of friction.
  943.                     g_AmmoQ[A].vVelocity.x *= 0.9f;
  944.                     g_AmmoQ[A].vVelocity.z *= 0.9f;
  945.                 }
  946.  
  947.                 // If the Y direction motion is below a certain threshold, flag the instance as
  948.                 // laying on the ground.
  949.                 if( GRAVITY * ( g_AmmoQ[A].vPosition.y + GROUND_Y - ( AMMO_SIZE * 0.5f ) ) + 0.5f * g_AmmoQ[A].vVelocity.y * g_AmmoQ[A].vVelocity.y
  950.                     < REST_THRESHOLD )
  951.                 {
  952.                     // Align the ball with the ground.
  953.                     g_AmmoQ[A].vPosition.y = -GROUND_Y + ( AMMO_SIZE * 0.5f );
  954.  
  955.                     // Y direction velocity becomes 0.
  956.                     g_AmmoQ[A].vVelocity.y = 0.0f;
  957.  
  958.                     // Flag it
  959.                     g_AmmoQ[A].bGround = true;
  960.                 }
  961.  
  962.                 // Check bounce on front and back walls
  963.                 if( g_AmmoQ[A].vPosition.z < g_MinBound.z + ( AMMO_SIZE * 0.5f ) )
  964.                 {
  965.                     // Align the ball with the wall.
  966.                     g_AmmoQ[A].vPosition.z = g_MinBound.z + ( AMMO_SIZE * 0.5f );
  967.  
  968.                     // Play sound
  969.                     g_AmmoQ[A].PlaySound( -g_AmmoQ[A].vVelocity.z );
  970.  
  971.                     // Invert the Z velocity
  972.                     g_AmmoQ[A].vVelocity.z = -g_AmmoQ[A].vVelocity.z * ( 1 - GROUND_ABSORBANCE );
  973.                 }
  974.                 if( g_AmmoQ[A].vPosition.z > g_MaxBound.z - ( AMMO_SIZE * 0.5f ) )
  975.                 {
  976.                     // Align the ball with the wall.
  977.                     g_AmmoQ[A].vPosition.z = g_MaxBound.z - ( AMMO_SIZE * 0.5f );
  978.  
  979.                     // Play sound
  980.                     g_AmmoQ[A].PlaySound( g_AmmoQ[A].vVelocity.z );
  981.  
  982.                     // Invert the Z velocity
  983.                     g_AmmoQ[A].vVelocity.z = -g_AmmoQ[A].vVelocity.z * ( 1 - GROUND_ABSORBANCE );
  984.                 }
  985.  
  986.                 // Check bounce on left and right walls
  987.                 if( g_AmmoQ[A].vPosition.x < g_MinBound.x + ( AMMO_SIZE * 0.5f ) )
  988.                 {
  989.                     // Align the ball with the wall.
  990.                     g_AmmoQ[A].vPosition.x = g_MinBound.x + ( AMMO_SIZE * 0.5f );
  991.  
  992.                     // Play sound
  993.                     g_AmmoQ[A].PlaySound( -g_AmmoQ[A].vVelocity.x );
  994.  
  995.                     // Invert the X velocity
  996.                     g_AmmoQ[A].vVelocity.x = -g_AmmoQ[A].vVelocity.x * ( 1 - GROUND_ABSORBANCE );
  997.                 }
  998.                 if( g_AmmoQ[A].vPosition.x > g_MaxBound.x - ( AMMO_SIZE * 0.5f ) )
  999.                 {
  1000.                     // Align the ball with the wall.
  1001.                     g_AmmoQ[A].vPosition.x = g_MaxBound.x - ( AMMO_SIZE * 0.5f );
  1002.  
  1003.                     // Play sound
  1004.                     g_AmmoQ[A].PlaySound( g_AmmoQ[A].vVelocity.x );
  1005.  
  1006.                     // Invert the X velocity
  1007.                     g_AmmoQ[A].vVelocity.x = -g_AmmoQ[A].vVelocity.x * ( 1 - GROUND_ABSORBANCE );
  1008.                 }
  1009.             }
  1010.  
  1011.             A = ( A + 1 ) % MAX_AMMO;
  1012.             if( A == g_nAmmoListTail ) break;
  1013.         }
  1014.     }
  1015. }
  1016.  
  1017.  
  1018. //--------------------------------------------------------------------------------------
  1019. // This callback function will be called at the end of every frame to perform all the 
  1020. // rendering calls for the scene, and it will also be called if the window needs to be 
  1021. // repainted. After this function has returned, the sample framework will call 
  1022. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  1023. //--------------------------------------------------------------------------------------
  1024. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  1025. {
  1026.     HRESULT hr;
  1027.     D3DXMATRIXA16 mView;
  1028.     D3DXMATRIXA16 mProj;
  1029.     D3DXMATRIXA16 mWorldView;
  1030.     D3DXMATRIXA16 mWorldViewProjection;
  1031.     
  1032.     // Clear the render target and the zbuffer 
  1033.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 45, 50, 170), 1.0f, 0) );
  1034.  
  1035.     // Render the scene
  1036.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  1037.     {
  1038.         // Get the projection & view matrix from the camera class
  1039.         mProj = *g_Camera.GetProjMatrix();
  1040.         mView = *g_Camera.GetViewMatrix();
  1041.  
  1042.         mWorldViewProjection = g_mCellWorld * mView * mProj;
  1043.         mWorldView = g_mCellWorld * mView;
  1044.  
  1045.         // Update the effect's variables.  Instead of using strings, it would 
  1046.         // be more efficient to cache a handle to the parameter by calling 
  1047.         // ID3DXEffect::GetParameterByName
  1048.         V( g_pEffect->SetMatrix( g_hMatV, &mView ) );
  1049.         V( g_pEffect->SetMatrix( g_hMatP, &mProj ) );
  1050.         V( g_pEffect->SetMatrix( g_hMatWVP, &mWorldViewProjection ) );
  1051.         V( g_pEffect->SetMatrix( g_hMatWV, &mWorldView ) );
  1052.         V( g_pEffect->SetMatrix( g_hMatW, &g_mCellWorld ) );
  1053.  
  1054.         pd3dDevice->SetFVF( g_Cell.m_pLocalMesh->GetFVF() );
  1055.         g_Cell.Render( g_pEffect, g_hTex, g_hDiffuse, 0, g_hSpecular, 0, g_hPower, true, false );
  1056.  
  1057.         pd3dDevice->SetFVF( g_Ball.m_pLocalMesh->GetFVF() );
  1058.         if( g_nAmmoCount > 0 )
  1059.             for( int A = g_nAmmoListHead; ; )
  1060.             {
  1061.                 D3DXMATRIXA16 mWorld;
  1062.                 D3DXMatrixTranslation( &mWorld, g_AmmoQ[A].vPosition.x,
  1063.                                                 g_AmmoQ[A].vPosition.y,
  1064.                                                 g_AmmoQ[A].vPosition.z );
  1065.                 mWorld = g_mBallWorld * mWorld;
  1066.                 mWorldViewProjection = mWorld * mView * mProj;
  1067.                 mWorldView = mWorld * mView;
  1068.                 V( g_pEffect->SetMatrix( g_hMatWVP, &mWorldViewProjection ) );
  1069.                 V( g_pEffect->SetMatrix( g_hMatWV, &mWorldView ) );
  1070.                 V( g_pEffect->SetMatrix( g_hMatW, &mWorld ) );
  1071.  
  1072.                 g_pEffect->SetTexture( g_hTex, g_pDefaultTex );
  1073.                 g_Ball.Render( g_pEffect, 0, g_hDiffuse, 0, g_hSpecular, 0, g_hPower, true, false );
  1074.  
  1075.                 A = ( A + 1 ) % MAX_AMMO;
  1076.                 if( A == g_nAmmoListTail ) break;
  1077.             }
  1078.  
  1079.         DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" ); // These events are to help PIX identify what the code is doing
  1080.         RenderText();
  1081.         V( g_HUD.OnRender( fElapsedTime ) );
  1082.         V( g_SampleUI.OnRender( fElapsedTime ) );
  1083.         DXUT_EndPerfEvent();
  1084.  
  1085.         V( pd3dDevice->EndScene() );
  1086.     }
  1087. }
  1088.  
  1089.  
  1090. //--------------------------------------------------------------------------------------
  1091. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  1092. // efficient text rendering.
  1093. //--------------------------------------------------------------------------------------
  1094. void RenderText()
  1095. {
  1096.     // The helper object simply helps keep track of text position, and color
  1097.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  1098.     // If NULL is passed in as the sprite object, then it will work however the 
  1099.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  1100.     const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  1101.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  1102.  
  1103.     // Output statistics
  1104.     txtHelper.Begin();
  1105.     txtHelper.SetInsertionPos( 5, 5 );
  1106.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  1107.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  1108.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  1109.  
  1110.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1111.     txtHelper.DrawTextLine( L"This sample is rendering with features enabled/disabled based\n"
  1112.                             L"on the display card model on the system.  Please see the documentation\n"
  1113.                             L"for complete information." );
  1114.  
  1115.     // List properties that have been applied.
  1116.     // Since IConfigDatabase only lives within CConfigManager::Initialize,
  1117.     // we check all properties and print them one by one.  This is ok since
  1118.     // this code is usually only used for informational purposes only.
  1119.     txtHelper.SetForegroundColor( D3DXCOLOR( 0.0f, 1.0f, 0.0f, 1.0f ) );
  1120.     int iY = pd3dsdBackBuffer->Height - 24;
  1121.     if( g_pCM->cf_ForceShader )
  1122.     {
  1123.         txtHelper.SetInsertionPos( 10, iY );
  1124.         switch( g_pCM->cf_ForceShader )
  1125.         {
  1126.             case 9999: txtHelper.DrawTextLine( L"ForceShader=0 (Shader is disabled)" ); break;
  1127.             case 9998: txtHelper.DrawTextLine( L"ForceShader=A2 (Forcing ps_2_a target)" ); break;
  1128.             case 9997: txtHelper.DrawTextLine( L"ForceShader=B2 (Forcing ps_2_b target)" ); break;
  1129.             default: txtHelper.DrawFormattedTextLine( L"ForceShader=%d (Forcing ps_%d_%d target)", g_pCM->cf_ForceShader, g_pCM->cf_ForceShader / 10, g_pCM->cf_ForceShader % 10 );
  1130.         }
  1131.         iY -= 16;
  1132.     }
  1133.     if( g_pCM->cf_InvalidSoundDriver )
  1134.     {
  1135.         txtHelper.SetInsertionPos( 10, iY );
  1136.         txtHelper.DrawTextLine( L"InvalidSoundDriver (Sound driver has problem with this application)" );
  1137.         iY -= 16;
  1138.     }
  1139.     if( g_pCM->cf_InvalidDriver )
  1140.     {
  1141.         txtHelper.SetInsertionPos( 10, iY );
  1142.         txtHelper.DrawTextLine( L"InvalidDriver (Display driver has problem with this application)" );
  1143.         iY -= 16;
  1144.     }
  1145.     if( g_pCM->cf_OldSoundDriver )
  1146.     {
  1147.         txtHelper.SetInsertionPos( 10, iY );
  1148.         txtHelper.DrawTextLine( L"OldSoundDriver (Sound driver is older than versions tested)" );
  1149.         iY -= 16;
  1150.     }
  1151.     if( g_pCM->cf_OldDriver )
  1152.     {
  1153.         txtHelper.SetInsertionPos( 10, iY );
  1154.         txtHelper.DrawTextLine( L"OldDriver (Display driver is older than versions tested)" );
  1155.         iY -= 16;
  1156.     }
  1157.     if( g_pCM->cf_UnsupportedCard )  // Should never see this. Included here anyways.
  1158.     {
  1159.         txtHelper.SetInsertionPos( 10, iY );
  1160.         txtHelper.DrawTextLine( L"UnsupportedCard (Display card is below requirement)" );
  1161.         iY -= 16;
  1162.     }
  1163.     if( g_pCM->cf_PrototypeCard )
  1164.     {
  1165.         txtHelper.SetInsertionPos( 10, iY );
  1166.         txtHelper.DrawTextLine( L"PrototypeCard (Display card is known prototype card)" );
  1167.         iY -= 16;
  1168.     }
  1169.     if( g_pCM->cf_DisableSpecular )
  1170.     {
  1171.         txtHelper.SetInsertionPos( 10, iY );
  1172.         txtHelper.DrawTextLine( L"DisableSpecular (Specular lighting is disabled)" );
  1173.         iY -= 16;
  1174.     }
  1175.     if( g_pCM->cf_UseFixedFunction )
  1176.     {
  1177.         txtHelper.SetInsertionPos( 10, iY );
  1178.         txtHelper.DrawTextLine( L"UseFixedFunction (Forcing fixed-function rendering path)" );
  1179.         iY -= 16;
  1180.     }
  1181.     if( g_pCM->cf_UseAnisotropicFilter )
  1182.     {
  1183.         txtHelper.SetInsertionPos( 10, iY );
  1184.         txtHelper.DrawTextLine( L"UseAnisotropicFilter (Anisotropic filtering for textures is enabled)" );
  1185.         iY -= 16;
  1186.     }
  1187.     if( g_pCM->cf_MaximumResolution )
  1188.     {
  1189.         txtHelper.SetInsertionPos( 10, iY );
  1190.         txtHelper.DrawFormattedTextLine( L"MaximumResolution=%d (Maximum resolution width is limited to %d)", g_pCM->cf_MaximumResolution, g_pCM->cf_MaximumResolution );
  1191.         iY -= 16;
  1192.     }
  1193.  
  1194.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1195.     txtHelper.SetInsertionPos( 5, iY - 4 );
  1196.     txtHelper.DrawTextLine( L"Config properties found:" );
  1197.  
  1198.     iY -= 24;
  1199.     txtHelper.SetInsertionPos( 5, iY );
  1200.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );
  1201.     if( g_pCM->cf_SafeMode )
  1202.         txtHelper.DrawTextLine( L"SAFE MODE\n" );
  1203.  
  1204.     // Draw help
  1205.     if( g_bShowHelp )
  1206.     {
  1207.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width-150, pd3dsdBackBuffer->Height-15*6 );
  1208.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  1209.         txtHelper.DrawTextLine( L"Controls (F1 to hide):" );
  1210.  
  1211.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width-130, pd3dsdBackBuffer->Height-15*5 );
  1212.         txtHelper.DrawTextLine( L"Move: W,S,A,D\n"
  1213.                                 L"Shoot: Left mouse\n"
  1214.                                 L"Rotate: Right mouse\n"
  1215.                                 L"Quit: ESC" );
  1216.     }
  1217.     else
  1218.     {
  1219.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width-150, pd3dsdBackBuffer->Height-15*2 );
  1220.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1221.         txtHelper.DrawTextLine( L"Press F1 for help" );
  1222.     }
  1223.     txtHelper.End();
  1224. }
  1225.  
  1226.  
  1227. //--------------------------------------------------------------------------------------
  1228. // Before handling window messages, the sample framework passes incoming windows 
  1229. // messages to the application through this callback function. If the application sets 
  1230. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  1231. //--------------------------------------------------------------------------------------
  1232. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  1233. {
  1234.     // Give the dialogs a chance to handle the message first
  1235.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  1236.     if( *pbNoFurtherProcessing )
  1237.         return 0;
  1238.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  1239.     if( *pbNoFurtherProcessing )
  1240.         return 0;
  1241.  
  1242.     // Pass all remaining windows messages to camera so it can respond to user input
  1243.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1244.  
  1245.     switch( uMsg )
  1246.     {
  1247.         case WM_ACTIVATEAPP:
  1248.             if( wParam )
  1249.                 DXUTPause( false, false );
  1250.             else
  1251.                 DXUTPause( true, true );
  1252.             break;
  1253.  
  1254.         case WM_LBUTTONDOWN:
  1255.         case WM_LBUTTONDBLCLK:
  1256.             g_bLeftMouseDown = true;
  1257.             break;
  1258.         case WM_LBUTTONUP:
  1259.             g_bLeftMouseDown = false;
  1260.             break;
  1261.     }
  1262.  
  1263.     return 0;
  1264. }
  1265.  
  1266.  
  1267. //--------------------------------------------------------------------------------------
  1268. // As a convenience, the sample framework inspects the incoming windows messages for
  1269. // keystroke messages and decodes the message parameters to pass relevant keyboard
  1270. // messages to the application.  The framework does not remove the underlying keystroke 
  1271. // messages, which are still passed to the application's MsgProc callback.
  1272. //--------------------------------------------------------------------------------------
  1273. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  1274. {
  1275.     if( bKeyDown )
  1276.     {
  1277.         switch( nChar )
  1278.         {
  1279.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  1280.         }
  1281.     }
  1282. }
  1283.  
  1284.  
  1285. //--------------------------------------------------------------------------------------
  1286. // Handles the GUI events
  1287. //--------------------------------------------------------------------------------------
  1288. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  1289. {
  1290.     switch( nControlID )
  1291.     {
  1292.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  1293.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  1294.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  1295.         case IDC_FIXEDFUNC:
  1296.         {
  1297.             g_pCM->cf_UseFixedFunction = ((CDXUTCheckBox*)pControl)->GetChecked();
  1298.             if( g_pCM->cf_UseFixedFunction )
  1299.                 g_pEffect->SetTechnique( "FFRenderScene" );
  1300.             else
  1301.                 g_pEffect->SetTechnique( g_hShaderTech );
  1302.             break;
  1303.         }
  1304.         case IDC_USEANISO:
  1305.         {
  1306.             g_pCM->cf_UseAnisotropicFilter = ((CDXUTCheckBox*)pControl)->GetChecked();
  1307.             g_pEffect->SetBool( "g_bUseAnisotropic", g_pCM->cf_UseAnisotropicFilter );
  1308.             g_pEffect->SetInt( "g_MinFilter", g_pCM->cf_UseAnisotropicFilter ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR );
  1309.             g_pEffect->SetInt( "g_MaxAnisotropy", g_pCM->cf_UseAnisotropicFilter ? 8 : 1 );
  1310.             break;
  1311.         }
  1312.         case IDC_DISABLESPECULAR:
  1313.         {
  1314.             g_pCM->cf_DisableSpecular = ((CDXUTCheckBox*)pControl)->GetChecked();
  1315.             g_pEffect->SetBool( "g_bUseSpecular", !g_pCM->cf_DisableSpecular );
  1316.             break;
  1317.         }
  1318.         case IDC_FORCESHADER:
  1319.         {
  1320.             g_pCM->cf_ForceShader = (DWORD)(size_t)((CDXUTComboBox*)pControl)->GetSelectedData();
  1321.             SetEffectTechnique();
  1322.             break;
  1323.         }
  1324.     }
  1325. }
  1326.  
  1327.  
  1328. //--------------------------------------------------------------------------------------
  1329. // This callback function will be called immediately after the Direct3D device has 
  1330. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  1331. // in the OnResetDevice callback should be released here, which generally includes all 
  1332. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  1333. // information about lost devices.
  1334. //--------------------------------------------------------------------------------------
  1335. void CALLBACK OnLostDevice()
  1336. {
  1337.     if( g_pFont )
  1338.         g_pFont->OnLostDevice();
  1339.     if( g_pEffect )
  1340.         g_pEffect->OnLostDevice();
  1341.     SAFE_RELEASE( g_pTextSprite );
  1342.     g_Cell.InvalidateDeviceObjects();
  1343.     g_Ball.InvalidateDeviceObjects();
  1344. }
  1345.  
  1346.  
  1347. //--------------------------------------------------------------------------------------
  1348. // This callback function will be called immediately after the Direct3D device has 
  1349. // been destroyed, which generally happens as a result of application termination or 
  1350. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  1351. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  1352. //--------------------------------------------------------------------------------------
  1353. void CALLBACK OnDestroyDevice()
  1354. {
  1355.     SAFE_RELEASE( g_pEffect );
  1356.     SAFE_RELEASE( g_pFont );
  1357.     SAFE_RELEASE( g_pDefaultTex );
  1358.     g_Cell.Destroy();
  1359.     g_Ball.Destroy();
  1360. }
  1361.